package net.maku.kyy.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import net.maku.api.module.system.SmsApi;
import net.maku.framework.common.constant.Constant;
import net.maku.framework.common.constant.MessageConstant;
import net.maku.framework.common.exception.ServerException;
import net.maku.framework.common.utils.HttpContextUtils;
import net.maku.framework.common.utils.IpUtils;
import net.maku.framework.security.cache.TokenStoreCache;
import net.maku.framework.security.user.UserDetail;
import net.maku.framework.security.utils.ThreadLocalUtil;
import net.maku.kyy.dao.KyyUserDao;
import net.maku.kyy.dto.KyyLoginDTO;
import net.maku.kyy.dto.KyyUserPasswordLoginDTO;
import net.maku.kyy.entity.KyyUserEntity;
import net.maku.kyy.service.KyyUserLoginService;
import net.maku.kyy.service.KyyUserService;
import net.maku.kyy.service.KyyUserTokenService;
import net.maku.kyy.service.KyyUserDetailsService;
import net.maku.kyy.vo.KyyUserTokenVO;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.util.Map;
import java.util.UUID;


@Slf4j
@Service
public class KyyUserLoginServiceImpl implements KyyUserLoginService {

    @Autowired
    private KyyUserService kyyUserService;
    @Autowired
    private KyyUserDao kyyUserDao;
    @Autowired
    private KyyUserTokenService kyyUserTokenService;
    @Autowired
    private TokenStoreCache tokenStoreCache;
    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private KyyUserDetailsService kyyUserDetailsService;
    @Autowired
    private SmsApi smsApi;



    @Value("${wechat.APP_ID}")
    private String APP_ID;

    @Value("${wechat.APP_SECRET}")
    private String APP_SECRET;
    /**
     * 表示账号
     */
    private final String IsAccount = "0";
    /**
     * 表示手机号
     */
    private final String IsMobile = "1";

    /**
     * 账号/手机号密码登录
     * @param kyyUserAccountLoginDTO
     * @return
     */
    @Transactional
    @Override
    public KyyUserTokenVO passwordLogin(KyyUserPasswordLoginDTO kyyUserAccountLoginDTO) {
        String accountOrPhone = kyyUserAccountLoginDTO.getAccountOrPhone();
        String password = kyyUserAccountLoginDTO.getPassword();

        /*// 判断账号或者手机号是否存在
        Boolean existAccountOrPhone = isExistAccountOrPhone(accountOrPhone);
        if (!existAccountOrPhone){
            throw new ServerException(MessageConstant.ACCOUNT_NOT_EXIST);
        }
        //获取用户信息
        //根据账号或者手机号查询用户信息
        KyyUserEntity kyyUserEntity = kyyUserDao.selectOne(new QueryWrapper<KyyUserEntity>().eq("account", accountOrPhone).or().eq("mobile", accountOrPhone));
        //密码解密
        String password = Sm2Util.decrypt(kyyUserEntity.getPassword());
        if (!StrUtil.equals(password, kyyUserAccountLoginDTO.getPassword())){
            //密码错误
            throw new ServerException(MessageConstant.PASSWORD_ERROR);
        }
        //创建 accessToken
//        SysUserTokenVO userTokenVO = sysUserTokenService.createToken(kyyUserEntity.getId());
        KyyUserTokenVO userTokenVO = kyyUserTokenService.createToken(kyyUserEntity.getId());
        UserDetail userDetail = BeanUtil.copyProperties(kyyUserEntity, UserDetail.class);*/

        Authentication authentication;
        try {
            authentication=authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(accountOrPhone, password));
        } catch (BadCredentialsException e) {
            throw new ServerException(MessageConstant.PASSWORD_ERROR);
        }

        UserDetail userDetail = (UserDetail) authentication.getPrincipal();
        userDetail.setUserType(Constant.KYY_TYPE);
        
        // 确保用户有权限集合
        if (userDetail.getAuthoritySet() == null) {
            userDetail = (UserDetail) kyyUserDetailsService.getUserDetails(userDetail);
        }

        KyyUserTokenVO userTokenVO = kyyUserTokenService.createToken(userDetail.getId());


        //保存登录信息
        HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
        String ip = IpUtils.getIpAddr(request);
        kyyUserDao.updateIpById(userDetail.getId(),ip);

        //保存用户信息到redis缓存
        tokenStoreCache.saveKyyUser(userTokenVO.getAccessToken(), userDetail);

        log.info(userDetail.getMobile()+"用户成功登录");
        return userTokenVO;
    }

    /**
     * 微信登录
     * @param code
     * @return
     */
    @Transactional
    @Override
    public KyyUserTokenVO wechatLogin(String code) {
        if (StrUtil.isBlank(code)){
            throw new ServerException(MessageConstant.WEACHAT_ERROR);
        }
        // 发送请求通过code获取 access_token 和 openid
        //创建access_token的链接
        String url="https://api.weixin.qq.com/sns/oauth2/access_token?appid="+APP_ID+
                "&secret="+APP_SECRET+"&code="+code+"&grant_type=authorization_code";
        //发送请求
        //创建httpClient
        CloseableHttpClient httpClient = HttpClients.createDefault();
        //创建get请求
        HttpGet httpGet = new HttpGet(url);
        KyyUserTokenVO userTokenVO;
        try {
            //发送请求并获取响应
            CloseableHttpResponse response = httpClient.execute(httpGet);
            //解析响应
            String responseBody = EntityUtils.toString(response.getEntity());
            //解析响应为 JSON 对象
            JSONObject jsonObject = new JSONObject(responseBody);
            if (jsonObject.getInt("errcode")!=0){
                //获取失败
                throw new ServerException(MessageConstant.WEACHAT_ERROR);
            }
            // 获取 access_token 和 openid
            String accessToken = jsonObject.getStr("access_token");
            String openId = jsonObject.getStr("openid");
            //获取用户的信息
            //创建获取用户信息的链接
            String userInfoUrl = "https://api.weixin.qq.com/sns/userinfo?access_token=" + accessToken +
                    "&openid=" + openId;
            //发送请求并获取响应
            HttpGet userInfoHttpGet = new HttpGet(userInfoUrl);
            CloseableHttpResponse userInfoResponse = httpClient.execute(userInfoHttpGet);
            //解析响应
            String userInfoBody = EntityUtils.toString(userInfoResponse.getEntity());
            //解析响应为 JSON 对象
            JSONObject userInfoJson = new JSONObject(userInfoBody);
            if (jsonObject.getInt("errcode")!=0){
                //获取失败
                throw new ServerException(MessageConstant.WEACHAT_ERROR);
            }
            // 获取微信用户的信息
            String userOpenId=userInfoJson.getStr("openid");
            String wechatId = userInfoJson.getStr("unionid");
            String nickname = userInfoJson.getStr("nickname");
            String iconUrl = userInfoJson.getStr("headimgurl");
            //判断根据微信号用户是否存在
            //获取用户的手机号

//            String phoneUrl="https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token="+accessToken;
            String phoneUrl = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=" + accessToken + "&code=" + code;

            HttpPost httpPost = new HttpPost(phoneUrl);
            CloseableHttpResponse userPhoneResponse = httpClient.execute(httpPost);
            String phoneBody = EntityUtils.toString(userPhoneResponse.getEntity());
            JSONObject userPhoneJson = new JSONObject(phoneBody);
            //获取手机号
            String phone = userPhoneJson.getStr("phoneNumber");

//            //判断用户是否存在
            Boolean existPhone = isExistPhone(phone);
            if (!existPhone){
                //随机生成一个账号
                //不存在获取一个10位数新的账号
                String account= getAccount();
                KyyUserEntity kyyUserEntity = KyyUserEntity.builder()
                        .nickName(nickname)
                        .account(account)
                        .wechatId(wechatId)
                        .mobile(phone)
                        .status(Constant.USER_STATUS_NORMAL)//默认状态正常
                        .forumPermission(Long.valueOf(Constant.FORUM_PUBLISH_NORMAL_STR))//发布权限状态正常
                        .account(iconUrl)
                        .build();
                kyyUserDao.insert(kyyUserEntity);
            }
            //存在则获取用户信息
            KyyUserEntity kyyUserEntity = kyyUserDao.selectOne(new QueryWrapper<KyyUserEntity>().eq("wechatId", wechatId));
            //创建 accessToken
            userTokenVO = kyyUserTokenService.createToken(kyyUserEntity.getId());
            UserDetail userDetail = BeanUtil.copyProperties(kyyUserEntity, UserDetail.class);
            userDetail.setUserType(Constant.KYY_TYPE);
            
            // 通过KyyUserDetailsService设置用户权限
            userDetail = (UserDetail) kyyUserDetailsService.getUserDetails(userDetail);
            
            //保存用户信息到缓存 微信登录存储短期token
            tokenStoreCache.saveUser(userTokenVO.getAccessToken(),userDetail);
        } catch (IOException e) {
            throw new ServerException(MessageConstant.WEACHAT_ERROR);
        }
        return userTokenVO;

    }

    /**
     * 退出登录
     */
    @Override
    public void logout(String token) {
        Map map = ThreadLocalUtil.get();
        if (map==null){
            throw new ServerException(MessageConstant.PLEASE_LOGIN);
        }
        Long userId = (Long) map.get(Constant.KYY_USER_ID);
        tokenStoreCache.deleteKyyUser(token);
        //token过期
        kyyUserTokenService.expireToken(userId);
    }

    @Override
    public KyyUserTokenVO codeLogin(KyyLoginDTO kyyLoginDTO) {
        String phone = kyyLoginDTO.getPhone();
        String code = kyyLoginDTO.getCode();

        if(phone==null){
            throw new ServerException(MessageConstant.PHONE_NOT_NULL);
        }
        if (code==null){
            throw new ServerException(MessageConstant.CODE_ERROR);
        }

        // 验证短信验证码
        if(!smsApi.verifyCode("kyy:login:code:"+phone,code)){
            throw new ServerException(MessageConstant.CODE_ERROR);
        }
        
        // 查询用户信息
        QueryWrapper<KyyUserEntity> queryWrapper = new QueryWrapper<>();
        KyyUserEntity kyyUserEntity = kyyUserDao.selectOne(queryWrapper.eq("mobile", phone));
        if (kyyUserEntity==null){
            throw new ServerException(MessageConstant.ACCOUNT_NOT_EXIST);
        }
        
        // 直接使用用户ID创建token
        Long userId = kyyUserEntity.getId();
        KyyUserTokenVO userTokenVO = kyyUserTokenService.createToken(userId);
        
        // 创建UserDetail对象
        UserDetail userDetail = BeanUtil.copyProperties(kyyUserEntity, UserDetail.class);
        userDetail.setUserType(Constant.KYY_TYPE);
        
        // 获取用户权限
        userDetail = (UserDetail) kyyUserDetailsService.getUserDetails(userDetail);
        
        // 保存登录信息
        HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
        String ip = IpUtils.getIpAddr(request);
        kyyUserDao.updateIpById(userId, ip);
        
        // 保存用户信息到redis缓存
        tokenStoreCache.saveKyyUser(userTokenVO.getAccessToken(), userDetail);
        
        log.info(userDetail.getMobile() + "用户成功登录");
        return userTokenVO;
    }

    /**
     * 生成随机账号
     * @return
     */
    @NotNull
    public static String getAccount() {
        return UUID.randomUUID().toString().replace("-", "").substring(0, 10);
    }

    /**
     * 判断账号或者手机号是否存在
     * @param accountOrPhone
     * @return
     */
    public Boolean isExistAccountOrPhone(String accountOrPhone){
        if (isExistAccount(accountOrPhone)){
            return true;
        }
        if (isExistPhone(accountOrPhone)){
            return true;
        }
        return false;
    }

    /**
     * 判断该账号是否存在
     * @param account 账号
     * @return
     */
    public Boolean isExistAccount(String account){
        //根据账号或者手机号判断账号是否存在
        boolean exists = kyyUserDao.exists(new QueryWrapper<KyyUserEntity>().eq("account", account));
        return exists;
    }

    /**
     * 判断手机号是否存在
     * @param phone
     * @return
     */
    public Boolean isExistPhone(String phone){
        //根据手机号判断账号是否存在
        boolean exists = kyyUserDao.exists(new QueryWrapper<KyyUserEntity>().eq("mobile", phone));
        return exists;
    }




    /**
     * //根据账号查询用户
     * @param account
     * @return
     */
    public KyyUserEntity getUserByAccount(String account){
        KyyUserEntity kyyUserEntity = kyyUserService.getOne(new QueryWrapper<KyyUserEntity>().eq("account", account));
        return kyyUserEntity;
    }

    /**
     * 根据手机号查询用户
     * @param phone
     * @return
     */
    public KyyUserEntity getUserByPhone(String phone){
        KyyUserEntity kyyUserEntity = kyyUserService.getOne(new QueryWrapper<KyyUserEntity>().eq("phone", phone));
        return kyyUserEntity;
    }
}
